<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
 <head>
  <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  <title>使用 Register Globals</title>

 </head>
 <body><div class="manualnavbar" style="text-align: center;">
 <div class="prev" style="text-align: left; float: left;"><a href="security.errors.html">错误报告</a></div>
 <div class="next" style="text-align: right; float: right;"><a href="security.variables.html">用户提交的数据</a></div>
 <div class="up"><a href="security.html">安全</a></div>
 <div class="home"><a href="index.html">PHP Manual</a></div>
</div><hr /><div id="security.globals" class="chapter">
   <h1>使用 Register Globals </h1>

   <div class="warning"><strong class="warning">Warning</strong><p class="simpara">本特性已自
PHP 5.3.0 起<em class="emphasis">废弃</em>并将自 PHP 5.4.0
起<em class="emphasis">移除</em>。</p></div>
   <p class="para">
    可能 <acronym title="PHP: Hypertext Preprocessor">PHP</acronym> 中最具争议的变化就是从 <acronym title="PHP: Hypertext Preprocessor">PHP</acronym> <a href="http://www.php.net/releases/4_2_0.php" class="link external">&raquo;&nbsp;4.2.0</a>
    版开始配置文件中 <acronym title="PHP: Hypertext Preprocessor">PHP</acronym> 指令 <a href="ini.core.html#ini.register-globals" class="link">register_globals</a>
    的默认值从 on 改为 off 了。对此选项的依赖是如此普遍以至于很多人根本不知道它的存在而以为
    <acronym title="PHP: Hypertext Preprocessor">PHP</acronym> 本来就是这么工作的。本节会解释用这个指令如何写出不安全的代码，但要知道这个指令本身没有不安全的地方，误用才会。
   </p>
   <p class="para">
    当 register_globals 打开以后，各种变量都被注入代码，例如来自 <acronym title="Hyper Text Markup Language">HTML</acronym>
    表单的请求变量。再加上 <acronym title="PHP: Hypertext Preprocessor">PHP</acronym> 在使用变量之前是无需进行初始化的，这就使得更容易写出不安全的代码。这是个很艰难的抉择，但
    <acronym title="PHP: Hypertext Preprocessor">PHP</acronym> 社区还是决定默认关闭此选项。当打开时，人们使用变量时确实不知道变量是哪里来的，只能想当然。但是
    register_globals 的关闭改变了这种代码内部变量和客户端发送的变量混杂在一起的糟糕情况。下面举一个错误使用 register_globals 的例子：
   </p>
   <p class="para">
    <div class="example" id="example-336">
     <p><strong>Example #1 错误使用 register_globals = on 的例子</strong></p>
     <div class="example-contents">
<div class="phpcode"><code><span style="color: #000000">
<span style="color: #0000BB">&lt;?php<br /></span><span style="color: #FF8000">//&nbsp;当用户合法的时候，赋值&nbsp;$authorized&nbsp;=&nbsp;true<br /></span><span style="color: #007700">if&nbsp;(</span><span style="color: #0000BB">authenticated_user</span><span style="color: #007700">())&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$authorized&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">true</span><span style="color: #007700">;<br />}<br /><br /></span><span style="color: #FF8000">//&nbsp;由于并没有事先把&nbsp;$authorized&nbsp;初始化为&nbsp;false，<br />//&nbsp;当&nbsp;register_globals&nbsp;打开时，可能通过GET&nbsp;auth.php?authorized=1&nbsp;来定义该变量值<br />//&nbsp;所以任何人都可以绕过身份验证<br /></span><span style="color: #007700">if&nbsp;(</span><span style="color: #0000BB">$authorized</span><span style="color: #007700">)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;include&nbsp;</span><span style="color: #DD0000">"/highly/sensitive/data.php"</span><span style="color: #007700">;<br />}<br /></span><span style="color: #0000BB">?&gt;</span>
</span>
</code></div>
     </div>

    </div>
   </p>
   <p class="para">
    当 register_globals = on 的时候，上面的代码就会有危险了。如果是
    off，<var class="varname"><var class="varname">$authorized</var></var> 就不能通过如 URL
    请求等方式来改变，这样就好多了，尽管初始化变量是一个良好的编程习惯。比如说，如果在上面的代码执行之前加入
    <em>$authorized = false</em> 的话，无论 register_globals 是 on 还是
    off 都可以，因为用户状态被初始化为未经认证。
   </p>
   <p class="para">
    另一个例子是关于<a href="ref.session.html" class="link">会话</a>的。当 register_globals = on
    的时候，<var class="varname"><var class="varname">$username</var></var> 也可以用在下面的代码中，但要意识到
    <var class="varname"><var class="varname">$username</var></var> 也可能会从其它途径进来，比如说通过 <acronym title="Uniform Resource Locator">URL</acronym> 的 GET。
   </p>
   <p class="para">
    <div class="example" id="example-337">
     <p><strong>Example #2 使用会话时同时兼容 register_globals on 和 off 的例子</strong></p>
     <div class="example-contents">
<div class="phpcode"><code><span style="color: #000000">
<span style="color: #0000BB">&lt;?php<br /></span><span style="color: #FF8000">//&nbsp;我们不知道&nbsp;$username&nbsp;的来源，但很清楚&nbsp;$_SESSION&nbsp;是<br />//&nbsp;来源于会话数据<br /></span><span style="color: #007700">if&nbsp;(isset(</span><span style="color: #0000BB">$_SESSION</span><span style="color: #007700">[</span><span style="color: #DD0000">'username'</span><span style="color: #007700">]))&nbsp;{<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;</span><span style="color: #DD0000">"Hello&nbsp;&lt;b&gt;</span><span style="color: #007700">{</span><span style="color: #0000BB">$_SESSION</span><span style="color: #007700">[</span><span style="color: #DD0000">'username'</span><span style="color: #007700">]}</span><span style="color: #DD0000">&lt;/b&gt;"</span><span style="color: #007700">;<br /><br />}&nbsp;else&nbsp;{<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;</span><span style="color: #DD0000">"Hello&nbsp;&lt;b&gt;Guest&lt;/b&gt;&lt;br&nbsp;/&gt;"</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;</span><span style="color: #DD0000">"Would&nbsp;you&nbsp;like&nbsp;to&nbsp;login?"</span><span style="color: #007700">;<br /><br />}<br /></span><span style="color: #0000BB">?&gt;</span>
</span>
</code></div>
     </div>

    </div>
   </p>
   <p class="para">
    采取相应的预防措施以便在伪造变量输入的时候给予警告是完全有可能的。如果事先确切知道变量是哪里来的，就可以检查所提交的数据是否是从不正当的表单提交而来。不过这不能保证变量未被伪造，这需要攻击者去猜测应该怎样去伪造。如果不在乎请求数据来源的话，可以使用
    <var class="varname"><var class="varname"><a href="reserved.variables.request.html" class="classname">$_REQUEST</a></var></var> 数组，它包括了 GET、POST 和 COOKIE
    的所有数据。详情可参见本手册的<a href="language.variables.external.html" class="link">来自 PHP 之外的变量</a>。
   </p>
   <p class="para">
    <div class="example" id="example-338">
     <p><strong>Example #3 探测有害变量</strong></p>
     <div class="example-contents">
<div class="phpcode"><code><span style="color: #000000">
<span style="color: #0000BB">&lt;?php<br /></span><span style="color: #007700">if&nbsp;(isset(</span><span style="color: #0000BB">$_COOKIE</span><span style="color: #007700">[</span><span style="color: #DD0000">'MAGIC_COOKIE'</span><span style="color: #007700">]))&nbsp;{<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #FF8000">//&nbsp;MAGIC_COOKIE&nbsp;来自&nbsp;cookie<br />&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;这样做是确保是来自&nbsp;cookie&nbsp;的数据<br /><br /></span><span style="color: #007700">}&nbsp;elseif&nbsp;(isset(</span><span style="color: #0000BB">$_GET</span><span style="color: #007700">[</span><span style="color: #DD0000">'MAGIC_COOKIE'</span><span style="color: #007700">])&nbsp;||&nbsp;isset(</span><span style="color: #0000BB">$_POST</span><span style="color: #007700">[</span><span style="color: #DD0000">'MAGIC_COOKIE'</span><span style="color: #007700">]))&nbsp;{<br /><br />&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">mail</span><span style="color: #007700">(</span><span style="color: #DD0000">"admin@example.com"</span><span style="color: #007700">,&nbsp;</span><span style="color: #DD0000">"Possible&nbsp;breakin&nbsp;attempt"</span><span style="color: #007700">,&nbsp;</span><span style="color: #0000BB">$_SERVER</span><span style="color: #007700">[</span><span style="color: #DD0000">'REMOTE_ADDR'</span><span style="color: #007700">]);<br />&nbsp;&nbsp;&nbsp;echo&nbsp;</span><span style="color: #DD0000">"Security&nbsp;violation,&nbsp;admin&nbsp;has&nbsp;been&nbsp;alerted."</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;exit;<br /><br />}&nbsp;else&nbsp;{<br /><br />&nbsp;&nbsp;&nbsp;</span><span style="color: #FF8000">//&nbsp;这一次请求中并没有设置&nbsp;MAGIC_COOKIE&nbsp;变量<br /><br /></span><span style="color: #007700">}<br /></span><span style="color: #0000BB">?&gt;</span>
</span>
</code></div>
     </div>

    </div>
   </p>
   <p class="para">
    当然，单纯地关闭 register_globals
    并不代表所有的代码都安全了。对于每一段提交上来的数据，都要对其进行具体的检查。永远要验证用户数据和对变量进行初始化！把
    <span class="function"><a href="function.error-reporting.html" class="function">error_reporting()</a></span> 设为
    <strong><code>E_NOTICE</code></strong> 级别可以检查未初始化的变量。
   </p>
   <p class="para">
    更多关于模拟 register_globals 为 on 或 off 的信息，请见此
    <a href="faq.misc.html#faq.misc.registerglobals" class="link">FAQ</a>。
   </p>

   <blockquote class="note"><p><strong class="note">Note</strong>: <strong>Superglobal 可用性说明：</strong><br />
<p class="para">自 PHP 4.1.0 起可以使用 Superglobal 数组，例如  <var class="varname"><var class="varname"><a href="reserved.variables.get.html" class="classname">$_GET</a></var></var>，<var class="varname"><var class="varname"><a href="reserved.variables.post.html" class="classname">$_POST</a></var></var>，和
 <var class="varname"><var class="varname"><a href="reserved.variables.server.html" class="classname">$_SERVER</a></var></var>，等等。更多信息请阅读手册中的 <a href="language.variables.predefined.html" class="link">superglobals</a> 章节。</p></p></blockquote>

  </div>
<hr /><div class="manualnavbar" style="text-align: center;">
 <div class="prev" style="text-align: left; float: left;"><a href="security.errors.html">错误报告</a></div>
 <div class="next" style="text-align: right; float: right;"><a href="security.variables.html">用户提交的数据</a></div>
 <div class="up"><a href="security.html">安全</a></div>
 <div class="home"><a href="index.html">PHP Manual</a></div>
</div></body></html>
